using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DA.AnimGraph.Editor {
    public static class TypeRegisterUtility {
        /// <summary>
        /// 获取某个类型（或接口）的所有子类，在所有程序集中搜索
        /// </summary>
        public static List<Type> GetAllSubClasses(Type baseType) {
            List<Type> subClasses = new List<Type>();
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies) {
                foreach (Type type in assembly.GetTypes()) {
                    if ((type.IsSubclassOf(baseType) || (baseType.IsInterface && baseType.IsAssignableFrom(type))) && !type.IsAbstract) {
                        subClasses.Add(type);
                    }
                }
            }
            return subClasses;
        }

        /// <summary>
        /// 获取所有带有指定特性的类型，在所有程序集中搜索
        /// </summary>
        /// <returns> (带有特性的类型, 该类型的指定特性) </returns>
        public static List<(Type, T)> GetAllClassesByAttribute<T>() where T : Attribute {
            var attributeType = typeof(T);
            List<(Type, T)> outResult = new();
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies) {
                foreach (Type type in assembly.GetTypes()) {
                    var attr = (T)Attribute.GetCustomAttribute(type, attributeType);
                    if (attr != null) {
                        outResult.Add((type, attr));
                    }
                }
            }
            return outResult;
        }

        /// <summary>
        /// 获取所有带有指定特性的类型，且继承自指定类型、接口，在所有程序集中搜索
        /// </summary>
        public static List<(Type, T)> GetAllClassesByAttributeWhereBaseClass<T, I>() where T : Attribute {
            var result = GetAllClassesByAttribute<T>();
            var baseType = typeof(I);
            var result2 = result.Where(x =>
                (x.Item1.IsSubclassOf(baseType) || (baseType.IsInterface && baseType.IsAssignableFrom(x.Item1))) && !x.Item1.IsAbstract)
                .ToList();
            return result2;
        }
    }
}
